import { _decorator, BoxCollider2D, Animation, Component, ERaycast2DType, Node, PhysicsSystem2D, RigidBody2D, Vec3, v2, rect, Rect, Vec2 } from 'cc';
import { StateMachine } from '../fsm/StateMachine';
import { EntityFX } from '../EntityFX';
import { delay } from '../Util/AsyncUtils';
import { Physicsgroup, StateDefine } from './Config';
const { ccclass, property } = _decorator;

@ccclass('Actor')
export abstract class Actor extends Component {
    @property MoveSpeed: number = 10;

    @property(Node) groundCheck: Node = null;
    @property groundCheckDistance: Vec3 = new Vec3();
    @property(Node) wallCheck: Node = null;
    @property wallCheckDistance: Vec3 = new Vec3();
    @property(Animation) animation :Animation= null;

    fx: EntityFX = null;
    rigidBody: RigidBody2D | null = null;
    stateMgr: StateMachine<StateDefine> = new StateMachine();

    facingDir: number = 1;
    facingRight: boolean = true;

    @property(Node) AttackCheck: Node = null;
    @property AttackCheckR: number = 20;

    @property(Vec2) knockBackDirection: Vec2 = null;
    @property knockBackDuration: number = 100;
    isKnocked: boolean = false;

    public start() {
        this.fx = this.node.getComponent(EntityFX);
        this.rigidBody = this.node.getComponent(RigidBody2D);
    }
    public update(deltaTime: number) {
        this.stateMgr.update(deltaTime);
    }
    public damage(): void {
        this.fx.FlashFX();
        this.HitKnockBack();
    }
    async HitKnockBack(){
        this.isKnocked = true;
        this.rigidBody.linearVelocity = new Vec2(this.knockBackDirection.x*-this.facingDir,this.knockBackDirection.y);
        await delay(this.knockBackDuration);
        this.isKnocked = false;
    }
    public IsGroundDetected(): boolean {
        const start = this.groundCheck.getWorldPosition();
        const end = start.clone().add(this.groundCheckDistance);
        let results = PhysicsSystem2D.instance.raycast(start, end, ERaycast2DType.Any, Physicsgroup.Wall);
        return results.length > 0;
    }
    public IsWallDetected(): boolean {
        const start = this.wallCheck.getWorldPosition();
        const end = start.clone().add(this.wallCheckDistance);
        // console.info(start+" "+end);
        let results = PhysicsSystem2D.instance.raycast(start, end, ERaycast2DType.Any, Physicsgroup.Wall);
        return results.length > 0;
    }
    public IsAttackDetected(): boolean {
        const start = this.wallCheck.getWorldPosition();
        const end = start.clone().add(this.wallCheckDistance);
        let results = PhysicsSystem2D.instance.raycast(start, end, ERaycast2DType.Any, Physicsgroup.Wall);
        return results.length > 0;
    }
    public Flip(): void {
        this.facingDir *= -1;
        this.facingRight = !this.facingRight;
        this.wallCheckDistance = new Vec3(-1 * this.wallCheckDistance.x, 0, 0)
        this.node.setScale(this.facingDir, 1);
    }
    public FlipControl(_xVelocity: number) {
        if (_xVelocity > 0 && !this.facingRight) {
            this.Flip();
        } else if (_xVelocity < 0 && this.facingRight) {
            this.Flip();
        }
    }
    public ZeroVelocity() {
        if(this.isKnocked)return;
        this.rigidBody.linearVelocity = v2(0, 0);
    }
    public setVelocity(_xVelocity: number, _yVelocity: number) {
        
        if(this.isKnocked)return;
        this.rigidBody.linearVelocity = v2(_xVelocity, _yVelocity);
        this.FlipControl(_xVelocity);
    }
}


